package com.my.socket.aio.v3;

import com.google.common.base.Throwables;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * User: Alex Zhong
 * Date: 2016/6/17
 */
public class Server {
    private static final Logger LOGGER = LoggerFactory.getLogger(Server.class);

    public static void main(String[] args) throws Exception {
        int nThreads = Runtime.getRuntime().availableProcessors();
        AsynchronousChannelGroup asynchronousChannelGroup = AsynchronousChannelGroup.withFixedThreadPool(nThreads, new ThreadFactory() {

            private AtomicInteger index = new AtomicInteger(0);

            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "asynchronous-task-" + index.incrementAndGet());
            }
        });

        AsynchronousServerSocketChannel asynchronousServerSocketChannel = AsynchronousServerSocketChannel.open(asynchronousChannelGroup);
        InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 9999);
        asynchronousServerSocketChannel.bind(inetSocketAddress);

        asynchronousServerSocketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {
            @Override
            public void completed(AsynchronousSocketChannel asynchronousSocketChannel, Object attachment) {
                LOGGER.info("incoming socket: {}", asynchronousSocketChannel);
                ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                asynchronousSocketChannel.read(byteBuffer, attachment, new CompletionHandler<Integer, Object>() {
                    @Override
                    public void completed(Integer result, Object attachment) {
                        String request = new String(byteBuffer.array(), 0, result);
                        LOGGER.info("read: {}", request);

                        String response = request.toUpperCase();
                        asynchronousSocketChannel.write(ByteBuffer.wrap(response.getBytes()), attachment, new CompletionHandler<Integer, Object>() {
                            @Override
                            public void completed(Integer result, Object attachment) {
                                LOGGER.info("write: {}", response);
                            }

                            @Override
                            public void failed(Throwable exc, Object attachment) {
                                LOGGER.error("exception caught, the error is {}", Throwables.getStackTraceAsString(exc));
                            }
                        });
                    }

                    @Override
                    public void failed(Throwable exc, Object attachment) {
                        LOGGER.error("exception caught, the error is {}", Throwables.getStackTraceAsString(exc));
                    }
                });
            }

            @Override
            public void failed(Throwable exc, Object attachment) {
                LOGGER.error("exception caught, the error is {}", Throwables.getStackTraceAsString(exc));
            }
        });

        LOGGER.info("listen at {}", inetSocketAddress);
    }
}
